package com.flesler.componentas.core
{
	import flash.errors.IllegalOperationError;
	import flash.utils.Proxy;
	import flash.utils.flash_proxy;
	
	// TODO: Add builtin event support? or maybe leave that to a component
	
	public dynamic class Entity extends Proxy implements Destroyable
	{
		private var components:Array = [];
		
		public function Entity()
		{
		}
		
		// Utils
		
		private function getKey(name:*):String
		{
			return name is QName ? QName(name).localName : String(name);
		}
		
		private function findComponentWith(key:String):Object
		{
			for each (var component:Component in components)
				if (key in component)
					return component;
			
			throw new IllegalOperationError(key + ' is not defined within this entity');
		}
		
		private function index(component:Component):int
		{
			return components.indexOf(component);
		}
		
		// Component holder behavior
		
		public function isRegistered(component:Component):Boolean
		{
			return index(component) !== -1;	
		}
		
		public function register(component:Component):void
		{
			if (!isRegistered(component))
				components.push(component);
		}
		
		public function unregister(component:Component):void
		{
			if (isRegistered(component))
				components.splice(index(component), 1);
		}
		
		// Destroyable implementation
		
		public function destroy():void
		{
			for each (var component:Component in components)
				component.destroy();
			
			components = null;
		}
		
		// Wrappers to Proxy members to be used with inheritance
		
		protected function getProperty(key:String):Object
		{
			return findComponentWith(key)[key];
		}
		
		protected function setProperty(key:String, value:Object):void
		{
			findComponentWith(key)[key] = value;
		}
		
		protected function callProperty(key:String, args:Array):Object
		{
			var component:Object = findComponentWith(key);
			return component[key].apply(component, args);
		}
		
		// Proxy implementation
		
		override flash_proxy function hasProperty(name:*):Boolean
		{
			return findComponentWith(getKey(name)) !== null;
		}
		
		override flash_proxy function getProperty(name:*):*
		{
			return getProperty(getKey(name));
		}
		
		override flash_proxy function setProperty(name:*, value:*):void
		{
			setProperty(getKey(name), value);
		}
		
		override flash_proxy function callProperty(name:*, ...args):* 
		{
			return callProperty(getKey(name), args);
		}
		
		// Other public methods
		
		public function initialize():void
		{
			for each (var component:Component in components)
				component.initialize(this);
		}
	}
}